include(['PClass', 'Vector2', 'shapes.Point'], 

function(){
	
	declare('shapes.Line');
	Line = PClass.create({
		p1 : null,
		p2 : null,
		m : null,
		b : null,
		last  : null,
		color : 'black',
		init: function(p1, p2){
			var recalculateLine = this.recalculateLine;
			var selfish = this;
			this.p1 = new Point(p1.x, p1.y);
			this.p1._move = this.p1.move;
			this.p1.move = function(x,y){
				this._move(x,y);
				selfish.recalculateLine();
			};
			this.p2 = new Point(p2.x, p2.y);
			this.p2._move = this.p2.move;
			this.p2.move = function(x,y){
				this._move(x,y);
				selfish.recalculateLine();
			};
		},
		reset: function(x1,y1,x2,y2){
			if(arguments.length == 2){
				x2 = x1;
				y2 = y1;
				x1 = this.p1.x;
				y1 = this.p1.y;
			}		
			this.p1.x = x1;
			this.p1.y = y1;
			this.p2.x = x2;
			this.p2.y = y2;
			
			this.recalculateLine();
		},
		recalculateLine : function(){
			var x1 = this.p1.x;
			var x2 = this.p2.x;
			var y1 = this.p1.y;
			var y2 = this.p2.y;
			this.m = (y1 - y2) / (x1 - x2);
			this.b = y1 - (this.m * x1);
		},
		move : function(x, y){
			if( this.last ){
				this.p1.reset(this.last.p1.x, this.last.p1.y);
				this.p2.reset(this.last.p2.x, this.last.p2.y);
			}else{
				this.last = {}
				this.last.p1 = new Point(this.p1.x, this.p1.y);
				this.last.p2 = new Point(this.p2.x, this.p2.y);
			}
			this.reset(this.p1.x+x, this.p1.y+y, this.p2.x+x, this.p2.y+y);
		},
		extrude: function(v){
			var p1 = this.p1;
			var p4 = this.p2;
			var p2 = new Vector2(p1.x, p1.y+v.y);
			var p3 = new Vector2(p1.x+v.x, p1.y+v.y);
			return new Quad(p1, p2, p3, p4);
		},
		render : function(gw){
			var c = gw.c;
			c.beginPath();
			c.strokeStyle = this.color;
			c.lineWidth = 1;
			var points = this.meshData();
			var p = points[0];
			c.moveTo(p.x | 0, p.y | 0);
			for(var i=0; i < points.length; i++){
				var index = (i+1)%points.length;
				p = points[index];
				c.lineTo(p.x | 0, p.y | 0);
			}
			c.stroke();
			this.p1.render(gw);
			this.p2.render(gw);
		},
		setActive : function(value){
			//console.log("Active: " + value);
			this.color = (value ? 'orange' : 'black');
			if(!value){
				this.p1.setActive(value);
				this.p2.setActive(value);
				this.last = null;
			}
		},
		intersects : function( point, tolerance ){
			tolerance = tolerance || 3
			var y = this.m * point.x + this.b;
			var intersects = point.y-tolerance <= y && y <= point.y+tolerance;
			if( intersects ){
				console.log("Line intersection: " + intersects + " y (" + y + " == " + point.y +") ~" + tolerance);
				var result = [this];
				if( Point.intersection(this.p1, point, tolerance) )
					result.push(this.p1);
				if( Point.intersection(this.p2, point, tolerance) )
					result.push(this.p2);
				return result;
			}
			return null;
		},
		lines : function(){
			return [this];
		},
		meshData : function(){
			return [this.p1, this.p2];
		}
	}, 'Line');
	
	Line.intersection = function(line1, line2){
		var b = line1.b - line2.b;
		var coef = line2.m - line1.m;
		var x = b / coef;
		var y = (line1.m * x) + line1.b;
		return new Point(x,y);
	};
	
});